<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BRole
 *
 * @author I062261
 */
class BRole extends BGroup {

    const Role_Space_Admin = 'space_admin';
    const Role_Space_Member = 'space_member';
    const Role_Space_customer = 'space_customer';
    const Role_App_Root = 'app_root';
    const Role_App_Admin = 'app_admin';
    const Role_App_Member = 'app_member';
    const Role_App_customer = 'app_customer';
    const All_Roles = 'all_roles';
    const Not_Exit_Role = 'not_exist_role';
    const Role_Group = 'role_group';
    const Role_Group_AllowJoinRole = 'allowJoinRole';
    const Role_Group_AutoJoinRole = 'autoJoinRole';

    public $name = null;
    public $description = null;
    public $spaceId = null;
    public $appId = null;
    public $data = array();

    public static function find($context) {
        $roles = self::findAll($context);
        if (is_array($roles) && $roles != NULL)
            return reset($roles);
    }

    public static function findAll($context, $recursive = FALSE, &$recursiveRoles = array()) {

        $root = self::getRoot();
        return $root->getChildren($context, $recursive, $recursiveRoles);
    }

    /**
     * 
     * @param type $role, can be role instance
     * role name and role id
     */
    public function addChildRole($role) {
        $childRole = NULL;

        if ($role instanceof BRole)
            $childRole = $role;

        if (is_numeric($role))
            $childRole = new BRole($role);

        if (is_string($role)) {
            $name = $role;
            $childRole = BRole::find(array('name' => $name, 'spaceId' => $this->spaceId, 'appId' => $this->appId));
            //if role not exist, create role first and then add it as child role
            if ($childRole == NULL) {
                $childRole = new BRole();
                $childRole->name = $name;
                $childRole->description = $name;
                $childRole->spaceId = $this->spaceId;
                $childRole->appId = $this->appId;
                $childRole->save();
            }
        }

        return parent::addChildItem($childRole);
    }

    /**
     * @return array Description, return array or role instance
     * @param mix $role, can be instance of brole
     * role name, string of role name, array or roles
     */
    public static function parseRolesIntoObjectList($roles, $app = NULL) {

        $retRoles = array();
        if (!$app instanceof BApp)
            $app = Blyn::app()->getActiveApp();

        if ($roles instanceof BRole)
            $retRoles[$roles->getId()] = $roles;

        if (is_string($roles)) {
            $roles = preg_split("/[,;]/", $roles);

            foreach ($roles as $role) {
                $appRole = $app->getRole($role);
                if ($appRole instanceof BRole)
                    $retRoles[$appRole->getId()] = $appRole;
            }
        }

        if (is_array($roles) && $roles != NULL) {
            foreach ($roles as $role) {
                if ($role instanceof BRole)
                    $retRoles[$role->getId()] = $role;
                else {
                    $appRole = $app->getRole($role);
                    if ($appRole instanceof BRole)
                        $retRoles[$appRole->getId()] = $appRole;
                }
            }
        }

        if ($retRoles != NULL)
            return $retRoles;

        return FALSE;
    }

    public static function findUserRolesReloaded($user = null, $context = NULL, $recursive = FALSE, $reloaded = false) {

        if (!$reloaded)
            $userRolesCache = Blyn::app()->getCacheManager()->getCache('userRolesCache');
        else
            $userRolesCache = array();

        $spaceId = isset($context['spaceId']) ? $context['spaceId'] : NULL;
        $appId = isset($context['appId']) ? $context['appId'] : NULL;

        $cacheId = '';
        if ($spaceId == NULL)
            $cacheId .= 's_0';
        else
            $cacheId .='s_' . $spaceId;

        if ($appId == NULL)
            $cacheId .= '_a_0';
        else
            $cacheId .= '_a_' . $appId;

        if (isset($userRolesCache[$cacheId]) && $userRolesCache[$cacheId] != NULL)
            return $userRolesCache[$cacheId];

        if ($user == NULL)
            $user = Blyn::app()->getCurrentUser();

        if (is_numeric($user) && $user > 0)
            $user = new BUser($user);

        if ($context == NULL)
            $context = array();

        $userRoles = $user->getGroups(new BRole(), $recursive);
        $appRoles = BRole::findAll($context, TRUE);

        foreach ($userRoles as $key => $role) {
            if ($role->name == BTreeEntity::node_root || $role->getName() == BRole::Role_App_Root) {
                unset($userRoles[$key]);
                //break;
            }
            if ($spaceId != NULL) {
                if ($role->spaceId != $spaceId && $role->spaceId > 0)
                    unset($userRoles[$key]);
            }
        }

        if ($userRoles == NULL)
            $userRoles = array();

        if ($recursive) {
            $userCircles = $user->getGroups(new BCircle(), $recursive);
            if ($userCircles != NULL) {
                foreach ($userCircles as $circleId => $circle) {
                    $roles = self::findCircleRoles($circleId, $context, $recursive);
                    foreach ($roles as $id => $role) {
                        $userRoles[$id] = $role;
                    }
                }
            }

            $children = array();
            foreach ($userRoles as $id => $role) {
                if ($role instanceof BRole) {
                    $items = $role->getChildren($context, $recursive);
                    foreach ($items as $id => $role)
                        $children[$id] = $role;
                }
            }

            foreach ($children as $id => $role) {
                $userRoles[$id] = $role;
            }
        }

        if ($userRoles != NULL) {
            foreach ($userRoles as $key => $role) {
                if ($role->name == BTreeEntity::node_root || $role->getName() == BRole::Role_App_Root) {
                    unset($userRoles[$key]);
                    //break;
                }
                if ($spaceId != NULL) {
                    if ($role->spaceId != $spaceId && $role->spaceId > 0)
                        unset($userRoles[$key]);
                }
                /*
                  if ($appId != NULL) {
                  if ($role->appId != $appId && $role->appId > 0)
                  unset($userRoles[$key]);
                  }
                 * 
                 */
            }
            //return $userRoles;
        }

        if ($appId != NULL) {
            /*
              if ($role->appId != $appId && $role->appId > 0) {
              unset($userRoles[$key]);
              }
             * 
             */
            //this will find roles in specify app that is child of user role
            foreach ($userRoles as $uId => $uRole) {
                foreach ($appRoles as $aId => $aRole) {
                    if ($uRole->isParentOf($aRole))
                        $userRoles[$aId] = $aRole;
                }
            }
        }

        if ($userRoles == NULL)
            $userRoles = array();

        //always add allRole to user roles
        $allRole = BRole::find(BRole::All_Roles);
        $userRoles[$allRole->getId()] = $allRole;

        if ($userRolesCache == NULL)
            $userRolesCache = array();
        $userRolesCache[$cacheId] = $userRoles;
        Blyn::app()->getCacheManager()->addCache('userRolesCache', $userRolesCache);

        return $userRoles;
    }

    public static function findUserRoles($user = null, $context = NULL, $recursive = FALSE, $isReload = FALSE) {

        if ($isReload) {
            Blyn::app()->getCacheManager()->addReloadList('userRolesCache');
        }

        $userRolesCache = Blyn::app()->getCacheManager()->getCache('userRolesCache');

        $spaceId = isset($context['spaceId']) ? $context['spaceId'] : NULL;
        $appId = isset($context['appId']) ? $context['appId'] : NULL;

        $cacheId = '';
        if ($spaceId == NULL)
            $cacheId .= 's_0';
        else
            $cacheId .='s_' . $spaceId;

        if ($appId == NULL)
            $cacheId .= '_a_0';
        else
            $cacheId .= '_a_' . $appId;

        if (isset($userRolesCache[$cacheId]) && $userRolesCache[$cacheId] != NULL)
            return $userRolesCache[$cacheId];

        if ($user == NULL)
            $user = Blyn::app()->getCurrentUser();

        if (is_numeric($user) && $user > 0)
            $user = new BUser($user);

        if ($context == NULL)
            $context = array();

        $userRoles = $user->getGroups(new BRole(), $recursive);
        $appRoles = BRole::findAll($context, TRUE);

        foreach ($userRoles as $key => $role) {
            if ($role->name == BTreeEntity::node_root || $role->getName() == BRole::Role_App_Root) {
                unset($userRoles[$key]);
                //break;
            }
            if ($spaceId != NULL) {
                if ($role->spaceId != $spaceId && $role->spaceId > 0)
                    unset($userRoles[$key]);
            }
        }

        if ($userRoles == NULL)
            $userRoles = array();

        if ($recursive) {
            $userCircles = $user->getGroups(new BCircle(), $recursive);
            if ($userCircles != NULL) {
                foreach ($userCircles as $circleId => $circle) {
                    $roles = self::findCircleRoles($circleId, $context, $recursive);
                    foreach ($roles as $id => $role) {
                        $userRoles[$id] = $role;
                    }
                }
            }

            $children = array();
            foreach ($userRoles as $id => $role) {
                if ($role instanceof BRole) {
                    $items = $role->getChildren($context, $recursive);
                    foreach ($items as $id => $role)
                        $children[$id] = $role;
                }
            }

            foreach ($children as $id => $role) {
                $userRoles[$id] = $role;
            }
        }

        if ($userRoles != NULL) {
            foreach ($userRoles as $key => $role) {
                if ($role->name == BTreeEntity::node_root || $role->getName() == BRole::Role_App_Root) {
                    unset($userRoles[$key]);
                    //break;
                }
                if ($spaceId != NULL) {
                    if ($role->spaceId != $spaceId && $role->spaceId > 0)
                        unset($userRoles[$key]);
                }
                /*
                  if ($appId != NULL) {
                  if ($role->appId != $appId && $role->appId > 0)
                  unset($userRoles[$key]);
                  }
                 * 
                 */
            }
            //return $userRoles;
        }

        if ($appId != NULL) {
            /*
              if ($role->appId != $appId && $role->appId > 0) {
              unset($userRoles[$key]);
              }
             * 
             */
            //this will find roles in specify app that is child of user role
            foreach ($userRoles as $uId => $uRole) {
                foreach ($appRoles as $aId => $aRole) {
                    if ($uRole->isParentOf($aRole))
                        $userRoles[$aId] = $aRole;
                }
            }
        }

        if ($userRoles == NULL)
            $userRoles = array();

        //always add allRole to user roles
        $allRole = BRole::find(BRole::All_Roles);
        $userRoles[$allRole->getId()] = $allRole;

        if ($userRolesCache == NULL)
            $userRolesCache = array();
        $userRolesCache[$cacheId] = $userRoles;
        Blyn::app()->getCacheManager()->addCache('userRolesCache', $userRolesCache);

        return $userRoles;
    }

    public static function findCircleRoles($circle, $context = NULL, $recursive = FALSE, $recursiveItems = array()) {

        $tempRecursiveItems = $recursiveItems;

        if (is_numeric($circle) && $circle > 0)
            $circle = new BCircle($circle);

        if ($context == NULL)
            $context = array();

        $context['pairObjs'] = $circle;
        $context['mainObj'] = new BRole();

        //$relationObjs = BRelationshipEntity::findAll($context);
        $relationObjs = BPairEntity::buildPairEntity($context);

        //$circleRoles = array();

        foreach ($relationObjs as $relationObj) {
            $role = $relationObj->getMainObj();
            $recursiveItems[$role->getId()] = $role;
        }

        if ($recursive) {
            $parentCircles = $circle->getParent($recursive);

            foreach ($parentCircles as $circle) {
                $context['pairObjs'] = $circle;
                self::findCircleRoles($circle, $context, FALSE, $recursiveItems);
            }
        }

        //means first run before go to further recursive calling
        if ($tempRecursiveItems == NULL) {
            $finalRoles = array();
            foreach ($recursiveItems as $id => $role) {
                if ($role instanceof BRole) {
                    $recursiveRoles = $role->getParent($recursive, $context);
                    foreach ($recursiveRoles as $id => $role) {
                        $finalRoles[$id] = $role;
                    }
                }
            }
            return $finalRoles;
        }

        return $recursiveItems;
    }

    public function initTreeEntityBeforeFirstLoad($data = NULL) {
        self::addInitialRoles();
    }

    private static function addInitialRoles() {
        $role = new BRole();
        $role->name = self::All_Roles;
        $role->save();
        self::getRoot()->addChildItem($role);

        $role = new BRole;
        $role->name = self::Not_Exit_Role;
        $role->save();
        self::getRoot()->addChildItem($role);
    }

}

?>
